use axum::{
    Json,
    http::Request,
    response::Response,
    middleware::Next, body::Body
};
use http::HeaderMap;
use serde_json::{json, Value};
use redis::{Commands, RedisError};
use dotenv::dotenv;
use std::env;
use crate::{ code, rdb, uuid, query};

use super::{claims::{get_claims, get_req_claims}, jwt::{token_encode, Claims}};

// 生成 token 字符串，并将登录状态存入 redis
pub fn create_token_save_redis(data:Option<Value> ) -> Result<Json<Value>, Json<Value>>{
    if let Some(f) = data {
        dotenv().ok();
        let env_expire = env::var("EXPIRE").unwrap_or_default();
        let expire = if env_expire.is_empty() { config::EXPIRE as i64 } else { env_expire.parse::<i64>().unwrap_or(0) };

        let uuid = uuid::create();
        let tok = token_encode(
            query::i32(&f, "id")?,
            query::u32_op(&f, "cid")?, 
            query::i8_op(&f, "role")?,
            query::vec_i32_op(&f, "roles")?,
            query::str_op(&f, "name")?,
            query::str(&f, "username")?,
            Some(uuid.to_owned())
        )?;
        let mut conn = rdb::connect("0")?;
        let _:() = conn.set(&uuid, &tok).unwrap();
        let _:() = conn.expire(&uuid, expire).unwrap();
        // f["token"] = tok.into();
        let mut r = json!({});
        r["token"] = tok.into();
        r["name"] = f["name"].to_owned();
        r["role"] = f["role"].to_owned();
        r["roles"] = f["roles"].to_owned();
        r["department"] = f["department"].to_owned();
        code::data(r.to_owned())
    }else{
        code::fail(203)
    }
}
// 验证接口登录状态的中间件
pub async fn auth(req: Request<Body>, next: Next) -> Result<Response, Json<Value>>{
    get_req_claims(req, next, false, |d|auth_token(d)).await
}
// 登录验证 token 是否过期，并在一定时间内自动续签 token
pub fn auth_token(claims: Claims) -> Result<(), Json<Value>> {
    let key = &claims.uuid;
    let mut conn = rdb::connect("0")?;
    let k: Result<String, RedisError> = conn.get(&key);
    match k {
        Ok(_f) => {
            dotenv().ok();
            let env_expire = env::var("EXPIRE").unwrap_or_default();
            let expire = if env_expire.is_empty() { config::EXPIRE as i64 } else { env_expire.parse::<i64>().unwrap_or(0) };
            let exp:i32 = conn.ttl(&key).unwrap();           // 续签 token 过期时间
            if exp > 0 && exp < (expire as i32)/5{
                let _:() = conn.expire(&key, expire).unwrap();
            }
            Ok(())
        },
        _ => Err(code::fail_(202))
    }
}
// 退出登录
pub fn logout(headers:HeaderMap) -> Result<Json<Value>, Json<Value>>{
    let mut conn = rdb::connect("0")?;
    let tk = get_claims(headers)?;
    let rs: Result<(), redis::RedisError> = conn.del(tk.uuid);
    code::send_ok(rs)
}